package com.lightbend.akka.np_sharding

import akka.actor.{Actor, ActorInitializationException, ActorLogging, DeathPactException, OneForOneStrategy, Props, SupervisorStrategy}
import akka.cluster.sharding.ShardRegion

object CounterClusterConfig {

  final case class EntityEnvelope(entityId: String, payload: Any)
  final case class Get(entityId: String)
  val numberOfShards = 100 // 最大分片数

  val extractEntityId: ShardRegion.ExtractEntityId = {
    case EntityEnvelope(entityId, payload) => (entityId, payload)
    case msg@Get(entityId) => (entityId, msg)
  }

  val extractShardId: ShardRegion.ExtractShardId = {
    case EntityEnvelope(entityId, _) => (math.abs(entityId.hashCode) % numberOfShards).toString
    case Get(entityId) => (math.abs(entityId.hashCode) % numberOfShards).toString
    case ShardRegion.StartEntity(entityId) =>
      // StartEntity is used by remembering entities feature
      (math.abs(entityId.hashCode) % numberOfShards).toString
  }
}

class CounterSupervisor extends Actor {
  val counter = context.actorOf(Props[Counter], "theCounter")

  override val supervisorStrategy = OneForOneStrategy() {
    case _: IllegalArgumentException     ⇒ SupervisorStrategy.Resume
    case _: ActorInitializationException ⇒ SupervisorStrategy.Stop
    case _: DeathPactException           ⇒ SupervisorStrategy.Stop
    case _: Exception                    ⇒ SupervisorStrategy.Restart
  }

  def receive = {
    case msg ⇒ counter forward msg
  }
}

object Counter {
  case object Increment
  case object Decrement

  case object Stop
  final case class CounterChanged(delta: Int)
}

class Counter extends Actor with ActorLogging {

  import com.lightbend.akka.np_sharding.Counter._
  import com.lightbend.akka.np_sharding.CounterClusterConfig.Get

  import scala.concurrent.duration._

  context.setReceiveTimeout(120.seconds)

  val entityType: String = getClass.getSimpleName
  val entityId  : String = self.path.name

  override def preStart(): Unit = {
    log.debug("==>1. I was created...")
  }

  override def postStop(): Unit = {
    log.debug("==>4. I was stop...")
  }

  override def receive: Receive = {
    case Get(id) =>
      log.debug(s"==>2. $id established...")
    case it@Increment =>
      log.debug("==>3. I am increase...")
  }
}

























